/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package acousticfield3d.gui.panels;

import acousticfield3d.gui.MainForm;
import acousticfield3d.math.M;
import acousticfield3d.protocols.ArduinoMEGA64;
import acousticfield3d.protocols.ArduinoMEGA64_Anim;
import acousticfield3d.protocols.ArduinoNano;
import acousticfield3d.protocols.ArduinoNano16;
import acousticfield3d.protocols.DeviceConnection;
import acousticfield3d.protocols.DirectionalSpeakerFPGA;
import acousticfield3d.protocols.SimpleFPGA;
import acousticfield3d.protocols.ZynqFPGA;
import acousticfield3d.scene.Entity;
import acousticfield3d.simulation.AnimKeyFrame;
import acousticfield3d.simulation.Animation;
import acousticfield3d.simulation.Simulation;
import acousticfield3d.simulation.Transducer;
import acousticfield3d.utils.Parse;
import acousticfield3d.utils.TextFrame;
import java.util.List;

/**
 *
 * @author Asier
 */
public class TransControlPanel extends javax.swing.JPanel {    
    public static final int DEFAULT_DIVS_PER_PERIOD = 24; 
    
    final MainForm mf;
    
    DeviceConnection device = null;
    
    public TransControlPanel(MainForm mf) {
        this.mf = mf;
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        sendButton = new javax.swing.JButton();
        initSerialButton = new javax.swing.JButton();
        stopSerialButton = new javax.swing.JButton();
        switchButton = new javax.swing.JButton();
        sendAnimButton = new javax.swing.JButton();
        deviceCombo = new javax.swing.JComboBox();
        jLabel1 = new javax.swing.JLabel();
        phaseSpinner = new javax.swing.JSpinner();
        onButton = new javax.swing.JButton();
        offButton = new javax.swing.JButton();
        phaseUpButton = new javax.swing.JButton();
        phaseDownButton = new javax.swing.JButton();
        durationsText = new javax.swing.JTextField();
        durationsButton = new javax.swing.JButton();
        jTextField1 = new javax.swing.JTextField();

        sendButton.setText("Send");
        sendButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sendButtonActionPerformed(evt);
            }
        });

        initSerialButton.setText("Connect");
        initSerialButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                initSerialButtonActionPerformed(evt);
            }
        });

        stopSerialButton.setText("Disconnect");
        stopSerialButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopSerialButtonActionPerformed(evt);
            }
        });

        switchButton.setText("Switch");
        switchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                switchButtonActionPerformed(evt);
            }
        });

        sendAnimButton.setText("Seq");
        sendAnimButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sendAnimButtonActionPerformed(evt);
            }
        });

        deviceCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "MEGA", "SimpleFPGA", "Nano8", "Directional Speaker", "MEGA_Anim", "Nano16", "Zynq" }));

        jLabel1.setText("Phase");

        phaseSpinner.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
        phaseSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                phaseSpinnerStateChanged(evt);
            }
        });

        onButton.setText("On");
        onButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onButtonActionPerformed(evt);
            }
        });

        offButton.setText("Off");
        offButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                offButtonActionPerformed(evt);
            }
        });

        phaseUpButton.setText("+");
        phaseUpButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                phaseUpButtonActionPerformed(evt);
            }
        });

        phaseDownButton.setText("-");
        phaseDownButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                phaseDownButtonActionPerformed(evt);
            }
        });

        durationsText.setText("1 0");

        durationsButton.setText("Durations");
        durationsButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                durationsButtonActionPerformed(evt);
            }
        });

        jTextField1.setText("localhost");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(durationsText)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(initSerialButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 45, Short.MAX_VALUE)
                        .addComponent(stopSerialButton))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(phaseSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 64, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(phaseUpButton))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(sendButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(switchButton))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(sendAnimButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(durationsButton))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(onButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(offButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 150, Short.MAX_VALUE)
                        .addComponent(phaseDownButton))
                    .addComponent(jTextField1)
                    .addComponent(deviceCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(sendButton)
                    .addComponent(switchButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(sendAnimButton)
                    .addComponent(durationsButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(durationsText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(phaseSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(phaseUpButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(onButton)
                    .addComponent(offButton)
                    .addComponent(phaseDownButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(deviceCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(initSerialButton)
                    .addComponent(stopSerialButton))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void initSerialButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_initSerialButtonActionPerformed
       initComm( -1 );
    }//GEN-LAST:event_initSerialButtonActionPerformed

    private void stopSerialButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopSerialButtonActionPerformed
        stopComm();
    }//GEN-LAST:event_stopSerialButtonActionPerformed
    
    
    private void sendButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendButtonActionPerformed
        sendPattern();
    }//GEN-LAST:event_sendButtonActionPerformed

    private void switchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_switchButtonActionPerformed
        switchBuffers();
    }//GEN-LAST:event_switchButtonActionPerformed

    private void sendAnimButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sendAnimButtonActionPerformed
        sendAnim( mf.animPanel.getCurrentAnimation().getKeyFrames().getElements() );
    }//GEN-LAST:event_sendAnimButtonActionPerformed

    private void phaseSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_phaseSpinnerStateChanged
        final int value = (Integer) phaseSpinner.getValue();
        mf.transPanel.setTransPhase( stepsToPhase(value) );
    }//GEN-LAST:event_phaseSpinnerStateChanged

    private void onButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onButtonActionPerformed
        mf.transPanel.setTransAmp( 1 );
    }//GEN-LAST:event_onButtonActionPerformed

    private void offButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offButtonActionPerformed
        mf.transPanel.setTransAmp( 0 );
    }//GEN-LAST:event_offButtonActionPerformed

    public float stepsToPhase(float steps){
        
        final float phaseF = 2.0f * steps / getDivs();
        return phaseF;
    }
    
    public void addPhaseSteps(float steps){
        final float phaseF = stepsToPhase(steps);
        mf.transPanel.setTransPhase( "a" + phaseF );
    }
    
    private void phaseUpButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_phaseUpButtonActionPerformed
        addPhaseSteps(1);
    }//GEN-LAST:event_phaseUpButtonActionPerformed

    private void phaseDownButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_phaseDownButtonActionPerformed
        addPhaseSteps(-1);
    }//GEN-LAST:event_phaseDownButtonActionPerformed

    private void durationsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_durationsButtonActionPerformed
        if (device != null){
            final int[] durations = Parse.parseIntArray( durationsText.getText(), " ");
            device.sendDurations(durations);
        }
    }//GEN-LAST:event_durationsButtonActionPerformed


    public void initComm(int port){
        stopComm();
        
       
        final int index = deviceCombo.getSelectedIndex();
        if (index == 0){ //  ArduinoMEGA64
            device = new ArduinoMEGA64(); 
        }else if (index == 1){ //  SimpleFPGA
            device = new SimpleFPGA();
        }else if (index == 2){ // NANO
            device = new ArduinoNano();
        }else if (index == 3){ // Directional Speaker
            device = new DirectionalSpeakerFPGA();
        }else if (index == 4){ // MEGA Anim
            device = new ArduinoMEGA64_Anim();
        }else if (index == 5){ // Nano16
            device = new ArduinoNano16();
        }else if (index == 6){ //  SimpleFPGA
            device = new ZynqFPGA(jTextField1.getText());
        }else{
            device = new DeviceConnection();
        }
        if (index != 6) {
            device.connect( port ); //pop the GUI for selecting the port
        }
    }
    
    public void stopComm(){
        if (device != null){
            try{
                device.disconnect();
            }catch(Exception ex){}
            device = null;
        }
    }
    
    public void sendPattern(){
        if (device != null){
            device.sendPattern( mf.simulation.getTransducers(), mf.simulation.getPower());
        }
    }
    
    public void animFrame(int frame) {
        if (device != null){
            if (device instanceof ArduinoMEGA64_Anim){
                device.sendDurations( new int[]{frame} );
                
            }else{
                device.sendPattern( mf.simulation.getTransducers() , mf.simulation.getPower());
            }
        }
    }
    
    public void sendPattern(final List<Transducer> trans, float power){
        if (device != null){
            device.sendPattern( trans ,  power);
        }
    }
    
    public void switchBuffers(){
        if (device != null){
            device.switchBuffers();
        }
    }
    
    public void sendAnim(final List<AnimKeyFrame> keyFrames){
        if (device != null){
            device.sendAnim(keyFrames);
        }
    }

    public void offNextOnTransducerMenuActionPerformed() {                                                        
        final List<Entity> selection = mf.getSelection();
        final Simulation simulation = mf.getSimulation();
        
        if (selection.isEmpty()){
            return;
        }
        Entity e = selection.get(0);
        if (! (e instanceof Transducer)){
            return;
        }
        Transducer t = (Transducer)e;
        mf.transPanel.setTransAmp( 0.0f );
        int indexTrans = mf.simulation.getTransducers().indexOf( t );
        if(indexTrans == -1){
            return;
        }
        
        mf.clearSelection();
        if (indexTrans < simulation.getTransducers().size() - 1 ){
            selection.add( simulation.getTransducers().get( indexTrans + 1));
            mf.transPanel.setTransAmp( 1.0f );
        }
        
    }  
   
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox deviceCombo;
    private javax.swing.JButton durationsButton;
    private javax.swing.JTextField durationsText;
    private javax.swing.JButton initSerialButton;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JTextField jTextField1;
    private javax.swing.JButton offButton;
    private javax.swing.JButton onButton;
    private javax.swing.JButton phaseDownButton;
    private javax.swing.JSpinner phaseSpinner;
    private javax.swing.JButton phaseUpButton;
    private javax.swing.JButton sendAnimButton;
    private javax.swing.JButton sendButton;
    private javax.swing.JButton stopSerialButton;
    private javax.swing.JButton switchButton;
    // End of variables declaration//GEN-END:variables

    /*
    public void exportAnimation() {
        final StringBuilder sb = new StringBuilder();
        
        final Animation anim = mf.animPanel.getCurrentAnimation();
        if (anim == null) { return; }
        
        final List<AnimKeyFrame> keys =  anim.getKeyFrames().getElements();
        int nTrans = M.nearestPowerOfTwo( mf.simulation.getTransducers().size() );
        nTrans = M.max(nTrans, 8);
        sb.append("{");
        final int nKeys = keys.size();
        for(int ik = 0; ik < nKeys; ++ik){
            final AnimKeyFrame key = keys.get(ik);
            sb.append("{");
            final byte[] data = key.calcSignals01(nTrans, mf.transControlPanel.getDivs());
            final int nData = data.length;
            for(int in = 0 ; in < nData; ++in){
               sb.append( "0x" + Integer.toHexString( data[in] & 0xFF ) );
                if (in != nData-1){
                    sb.append(",");
                
            }
            if (ik != nKeys-1){
                sb.append("},\n");
            }else{
                sb.append("}}");
            }
        }
        
        TextFrame.showText("Animations", sb.toString(), this);
    }*/

    
    private int getDivs() {
        return (device != null) ? device.getDivs() : DEFAULT_DIVS_PER_PERIOD;
    }

   
    
}
